/*
This file contains the second serial optimization.
A "break" statement was added in order to skip unnecessary iterations
once a number that satisfies the product condition has been found.
*/

#include <stdio.h>
#include <math.h>
#include <omp.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>

using namespace std; 

int main(int argc, char *argv[]) {

    int i,j,k,l,limit,prod;
    double temp;

    if (argc<2) 
        return 0;

    limit = atoi(argv[1]);

	vector<int> * vectArray = new vector<int>[omp_get_num_procs()]; 
	//printf("Num Procs: %d\n\n", omp_get_num_procs()); 

	omp_set_dynamic(0); 	
	omp_set_num_threads(omp_get_num_procs()); 
	#pragma omp parallel for private(i, j, k, l) schedule(static, 100) 
	for (i=1;i<=limit;i++) 
	{
		bool stay = true; 
		for (j=i;j>=-i && stay; j--) 
		{
			if (j!=0){ 
				for (k=i/j;k>=-i/j && stay; k--) 
				{
					if (k!=0){
						for (l=i/(j*k);l<=-i/(j*k) && stay; l++) 
						{
							if (j*k*l == i) 
							{
                        		if ((fabs(1-(double)(l*k+j*l+j*k)))<1e-9)
								{
									vectArray[omp_get_thread_num()].push_back(i); 
									//printf("%d\n",i);
									//printf("i: %d\nj: %d\nk: %d\nl: %d\n\n", i, j, k, l);
									stay = false;  
								}
							}
						}
					}
				}
			}
		}
	}
	for(int x=1; x<omp_get_num_procs(); x++)
	{
		vectArray[0].insert(vectArray[0].end(), vectArray[x].begin(), vectArray[x].end()); 
	}
	/*
	for(int a=0; a<omp_get_num_procs(); a++)
	{
		//printf("Thread: %d\n", a);
		for(int b=0; b<vectArray[a].size(); b++)
		{
			printf("%d\n", vectArray[a][b]);
		}
		//printf("\n\n"); 
	}
	*/

	sort(vectArray[0].begin(), vectArray[0].end());

	for(int x=0; x<vectArray[0].size(); x++)
	{
		printf("%d\n", vectArray[0][x]);
	}

}
